package com.zhulong.saas.cloud.gateway.oauth2;

import org.springframework.security.core.Authentication;
import org.springframework.security.web.server.authentication.ServerAuthenticationConverter;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.util.List;

/**
 * 从请求中获取accessToken。
 * 先从Authorization中获取，如获取不到则从地址栏中获取accessToken参数
 */
public class BearerTokenServerAuthenticationConverter implements ServerAuthenticationConverter {

    private static final String AUTHORIZATION_HEAD_NAME = "Authorization";

    private static final String TOKEN_TYPE = "Bearer ";

    private String PARAM_NAME = "access_token";

    @Override
    public Mono<Authentication> convert(ServerWebExchange exchange) {
        String bearerToken = exchargeTokenFromHead(exchange);
        if (bearerToken == null) {
            bearerToken = exchargeTokenFromParam(exchange);
        }

        if (bearerToken == null) {
            return Mono.empty();
        }
        Authentication authentication = new BearerTokenAuthenticationToken(bearerToken);
        return Mono.just(authentication);
    }

    private String exchargeTokenFromHead(ServerWebExchange exchange) {
        List<String> bearerTokenList = exchange.getRequest().getHeaders().get(AUTHORIZATION_HEAD_NAME);
        return getBearerToken(bearerTokenList);
    }

    private String getBearerToken(List<String> bearerTokenList) {
        if (bearerTokenList == null) {
            return null;
        }
        String bearerToken = bearerTokenList.stream().filter(t -> t.startsWith(TOKEN_TYPE)).findFirst()
                .orElse(null);
        if (bearerToken != null) {
            bearerToken = bearerToken.substring(TOKEN_TYPE.length());
        }
        return bearerToken;
    }

    private String exchargeTokenFromParam(ServerWebExchange exchange) {
        List<String> bearerTokenList = exchange.getRequest().getQueryParams().get(PARAM_NAME);
        return this.getFormToken(bearerTokenList);
    }

    private String getFormToken(List<String> bearerTokenList) {
        if (bearerTokenList == null || bearerTokenList.isEmpty()) {
            return null;
        }
        return bearerTokenList.get(0);
    }

}
